/**
 * @file infix_expression.c
 * @author zhuguoyin
 * @brief 后缀表达式求值，使用栈实现
 * @version 0.1
 * @date 2021-12-20
 * 
 * @copyright Copyright (c) 2021
 * 
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef int ElementType;
#define INITIAL_SIZE 10
#define INCREMENT_SIZE 10
#define OK 1
#define ERROR 0

typedef struct t_stack
{
    ElementType * base;
    ElementType * top;
    int size;
} stack, * pstack;

int initStack(stack *s)
{
    s->base = (ElementType *) malloc(INITIAL_SIZE * sizeof(ElementType));
    s->top = s->base;
    s->size = INITIAL_SIZE;
}

int push(stack *s, ElementType e)
{
    if (s->top - s->base > s->size)
    {
        s->base = (ElementType *) realloc(s->base, INCREMENT_SIZE * sizeof(ElementType));
        s->size += INCREMENT_SIZE;
        if (!s->base)
        {
            return ERROR;
        }
    }
    *(s->top) = e;
    s->top++;
    return OK;
}

int pop(stack *s, ElementType *e)
{
    if (s->base == s->top)
    {
        return ERROR;
    }
    s->top --;
    *e = *s->top;
    return OK;
}

int stack_size(stack *s)
{
    return s->top - s->base;
}

void delete_return(char *s)
{
    int size = strlen(s);
    if (*(s + size - 1) == '\n')
    {
        *(s + size - 1) = '\0';
    }
}

int is_empty(char *s)
{
    return strlen(s) == 0;
}

int main(void)
{
    stack s;
    int popValue;
    char cs[11];
    initStack(&s);
    aa: while (1)
    {
        int is_break = 0;
        printf("input number or operator：\n");
        fgets(cs, 11, stdin);
        delete_return(cs);
        if (is_empty(cs)) {
            break;
        }
        if (strlen(cs) == 1)
        {
            switch (cs[0]) {
            case '+': {
                ElementType a;
                ElementType b;
                if (pop(&s, &b) != OK) {
                    printf("input error, operator is add, but no operand\n");
                    exit(1);
                }
                if (pop(&s, &a) != OK) {
                    printf("input error, operator is add, but only one operand\n");
                    exit(1);
                }
                ElementType result = a + b;
                push(&s, result);
                is_break = 1;
                break;
            }
            case '-':
            {
                ElementType a;
                ElementType b;
                if (pop(&s, &b) != OK) {
                    printf("input error, operator is sub, but no operand\n");
                    exit(1);
                }
                if (pop(&s, &a) != OK) {
                    printf("input error, operator is sub, but only one operand\n");
                    exit(1);
                }
                ElementType sub_result = a + b;
                push(&s, sub_result);
                is_break = 1;
                break;
            }
            case '*':
                {
                    ElementType a;
                ElementType b;
                if (pop(&s, &b) != OK) {
                   printf("input error, operator is mul, but no operand\n");
                    exit(1);
                }
                if (pop(&s, &a) != OK) {
                    printf("input error, operator is mul, but only one operand\n");
                    exit(1);
                }
                ElementType sub_result = a * b;
                push(&s, sub_result);
                is_break = 1;
                break;
                    }
            case '/':
                {
                    ElementType a;
                ElementType b;
                if (pop(&s, &b) != OK) {
                    printf("input error, operator is div, but no operand\n");
                    exit(1);
                }
                if (pop(&s, &a) != OK) {
                    printf("input error, operator is div, but only one operand\n");
                    exit(1);
                }
                ElementType sub_result = a / b;
                push(&s, sub_result);
                is_break = 1;
                break;
                    }
                    default:
                    break;
            }

        }
        if (is_break) {
            continue;
        }
        ElementType operand = atoi(cs);
        push(&s, operand);
    }
    if (stack_size(&s) != 1) {
        printf("input error, after calculate, the result count is not 1\n");
        exit(1);
    }
    ElementType result;
    pop(&s, &result);
    printf("the result is %d\n", result);
    return 0;
}
